<template>
    <div ref="viewport" class="seamless-scroller" :style="{ height, width }" @mouseenter="pause" @mouseleave="resume">
        <div ref="content" class="scroller-content" :style="[transformStyle, contentLayout]">
            <!-- 第一组内容 -->
            <slot :items="items" :phase="'original'"></slot>
            <!-- 第二组克隆内容（横向时会正确排列在右侧/左侧） -->
            <div style="position: absolute; right: -100%; top: 0">
                <slot :items="items" :phase="'original'"></slot>
            </div>
        </div>
    </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from "vue";

const props = defineProps({
    items: { type: Array, required: true },
    direction: { type: String, default: "up" },
    speed: { type: Number, default: 30 },
    height: { type: String, default: "100vh" },
    width: { type: String, default: "100%" },
    pauseOnHover: { type: Boolean, default: true },
});

// 计算内容容器布局
const contentLayout = computed(() => {
    const isHorizontal = ["left", "right"].includes(props.direction);
    return {
        display: isHorizontal ? "inline-block" : "block",
        whiteSpace: isHorizontal ? "nowrap" : "normal",
    };
});

const emit = defineEmits(["scroll"]);

const viewport = ref(null);
const content = ref(null);
const scrollPos = ref(0);
let animId = 0;
let lastTime = 0;
let isPlaying = true;

// 计算transform样式
const transformStyle = computed(() => {
    const isVertical = ["up", "down"].includes(props.direction);
    const axis = isVertical ? "Y" : "X";
    const sign = ["up", "left"].includes(props.direction) ? "-" : "";
    return { transform: `translate${axis}(${sign}${scrollPos.value}px)` };
});

// 开始滚动
const startAnimation = (timestamp) => {
    if (!isPlaying) return;

    if (!lastTime) lastTime = timestamp;
    const delta = timestamp - lastTime;
    const deltaPx = (props.speed * delta) / 1000; // 转为px/帧

    scrollPos.value += deltaPx;

    // 检测是否滚动到克隆内容的起点
    if (content.value) {
        const contentSize = ["up", "down"].includes(props.direction) ? content.value.scrollHeight : content.value.scrollWidth;
        const maxScroll = contentSize / 2;

        if (scrollPos.value >= maxScroll) {
            scrollPos.value = 0; // 无缝跳回起点
        }
    }

    lastTime = timestamp;
    animId = requestAnimationFrame(startAnimation);
    emit("scroll", scrollPos.value);
};

// 控制方法
const pause = () => {
    if (props.pauseOnHover) {
        isPlaying = false;
    }
};
const resume = () => {
    if (props.pauseOnHover) {
        isPlaying = true;
        lastTime = 0; // 防止恢复时跳动
        animId = requestAnimationFrame(startAnimation);
    }
};

// 暴露控制方法
defineExpose({
    play: resume,
    pause,
    setSpeed: (speed) => {
        props.speed = speed;
    },
});

onMounted(() => {
    animId = requestAnimationFrame(startAnimation);
});

onBeforeUnmount(() => {
    cancelAnimationFrame(animId);
});
</script>

<style scoped>
.seamless-scroller {
    position: relative;
    overflow: hidden;
}

.scroller-content {
    position: absolute;
    display: flex;
    justify-content: space-around;
    will-change: transform;
}

/* 横向滚动时需要特殊处理 */
.scroller-content[data-direction="left"],
.scroller-content[data-direction="right"] {
    white-space: nowrap;
}
</style>
